// import com.alibaba.druid.FastsqlException;
// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.io.IOException;
// import java.util.Collections;
// import java.util.List;

#include "SQLIntervalExpr.h"
#include "../SQLDataTypeImpl.h"
#include "SQLIntervalUnit.h"
#include "../../../Exception/FastsqlException.h"
#include "../../visitor/SQLASTVisitor.h"

SQLDataType_ptr SQLIntervalExpr::DATA_TYPE = SQLDataType_ptr(new SQLDataTypeImpl(make_string_ptr("interval")));

SQLIntervalExpr::SQLIntervalExpr()
{
}

SQLIntervalExpr::SQLIntervalExpr(SQLExpr_ptr value, std::shared_ptr<SQLIntervalUnit> unit)
{
  setValue(value);
  this->unit = unit;
}

SQLObject_ptr SQLIntervalExpr::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLIntervalExpr>(new SQLIntervalExpr());
  std::shared_ptr<SQLIntervalExpr> x = std::dynamic_pointer_cast<SQLIntervalExpr>(clone_tmp);
  // SQLIntervalExpr x = new SQLIntervalExpr();
  if (value != nullptr)
  {
    x->setValue(std::dynamic_pointer_cast<SQLExpr>(value->clone()));
  }
  x->unit = unit;
  return x;
}

//@Override
BOOL_ptr SQLIntervalExpr::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  if (this->value == expr)
  {
    setValue(target);
    return BOOL::TRUE;
  }
  return BOOL::FALSE;
}

SQLExpr_ptr SQLIntervalExpr::getValue()
{
  return value;
}

void SQLIntervalExpr::setValue(SQLExpr_ptr x)
{
  if (x != nullptr)
  {
    x->setParent(SharedObject(SQLIntervalExpr));
  }
  this->value = x;
}

std::shared_ptr<SQLIntervalUnit> SQLIntervalExpr::getUnit()
{
  return unit;
}

void SQLIntervalExpr::setUnit(std::shared_ptr<SQLIntervalUnit> unit)
{
  this->unit = unit;
}

//@Override
void SQLIntervalExpr::output(std::stringstream *buf)
{
  try
  {
    (*buf) << "INTERVAL ";
    value->output(buf);
    if (unit != nullptr)
    {
      (*buf) << " ";
      (*buf) << *unit->name;
    }
    // } catch (IOException ex) {
  }
  catch (...)
  {
    // throw new FastsqlException("output error", ex);
    throw new FastsqlException(make_string_ptr("output error"));
  }
}

void SQLIntervalExpr::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLIntervalExpr)))
  {
    if (this->value != nullptr)
    {
      this->value->accept(visitor);
    }
  }
  visitor->endVisit(SharedObject(SQLIntervalExpr));
}

//@Override
SQLObject_list_ptr SQLIntervalExpr::getChildren()
{
  SQLObject_list_ptr tmp = SQLObject_list_ptr();
  tmp->push_back(value);
  return tmp;
}

//@Override
int SQLIntervalExpr::hashCode()
{
  int prime = 31;
  int result = 1;
  result = prime * result + ((unit == nullptr) ? 0 : unit->hashCode());
  result = prime * result + ((value == nullptr) ? 0 : value->hashCode());
  return result;
}

//@Override
bool SQLIntervalExpr::equals(Object_ptr obj)
{
  if (this == obj.get())
  {
    return true;
  }
  if (obj == nullptr)
  {
    return false;
  }
  if (getClass() != obj->getClass())
  {
    return false;
  }
  std::shared_ptr<SQLIntervalExpr> other = std::dynamic_pointer_cast<SQLIntervalExpr>(obj);
  if (unit != other->unit)
  {
    return false;
  }
  if (value == nullptr)
  {
    if (other->value != nullptr)
    {
      return false;
    }
  }
  else if (!value->equals(other->value))
  {
    return false;
  }
  return true;
}

SQLDataType_ptr SQLIntervalExpr::computeDataType()
{
  return DATA_TYPE;
}
